#include "CQHelper.h"
#include <fstream>
#include "../CQReflect/CQJson.hpp"

std::unordered_map<std::string, CQModule*> CQHelper::m_maker;
CQModule* CQHelper::CreateModule(const std::string& moduleName) {
	if (m_maker.find(moduleName) != m_maker.end()) {
		return m_maker[moduleName];
	}
	std::vector<CQModule*> out;
	HINSTANCE dll = LoadLibraryA((moduleName + ".dll").c_str());
	if (dll) {
		auto ModuleFuncPtr = (CQModule*)GetProcAddress(dll, CQCreaterStr.c_str());
		if (ModuleFuncPtr) {
			m_maker[moduleName] = ModuleFuncPtr;
		}
		return ModuleFuncPtr;
	}
	return nullptr;
}

void CQHelper::DeleteModule(const std::string& moduleName) {
	if (CQHelper::m_maker.find(moduleName) != CQHelper::m_maker.end()) {
		m_maker.erase(moduleName);
	}
}

CQ::CQVirtual* CQHelper::CreateInstance(const std::string& moduleName, const std::string& className, const std::string& paraStr) {
	auto ModuleFuncPtr = CreateModule(moduleName);
	if (ModuleFuncPtr)
		return ModuleFuncPtr(className, paraStr);
	return nullptr;
}

void CQHelper::DeleteInstance(CQ::CQVirtual* obj) {
	if (obj)
		delete obj;
	obj = nullptr;
}


std::vector<CQ::CQReflectStruct> parseConfig(const std::string& path)
{
	std::vector<CQ::CQReflectStruct> out;
	std::stringstream ss;
	std::string jsonStr, line;
	std::ifstream is(path);
	if (is.is_open()) {
		while (getline(is, line)) {
			ss << line;
		}
		jsonStr = ss.str();
		is.close();
	}
	CQJson::CQTinyJson json;
	json.ReadJson(jsonStr);

	std::string name = json.Get<std::string>("name");
	if (name != CQ::CQReflectName) return out;
	double ver = json.Get<double>("version");
	if (ver <= 1.0) return out;
	std::string lang = json.Get<std::string>("lang");
	if (lang != "cpp") return out;

	CQJson::CQArray data = json.Get<CQJson::CQArray>("data");
	for (int i = 0; i < data.Count(); ++i) {
		data.Enter(i);
		std::string moduleName = data.Get<std::string>("module");
		auto classNames = data.Get<CQJson::CQObject>("class");
		for (int j = 0; j < classNames.Count(); ++j) {
			classNames.Enter(j);
			CQ::CQReflectStruct ReflectObj;
			ReflectObj.moduleName = moduleName;
			ReflectObj.className = classNames.GetKey();
			ReflectObj.paraStr = classNames.Get<std::string>();
			out.push_back(ReflectObj);
		}
	}
	return out;
}